package com.yupi.yuaicodemother.service.impl;

import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.yupi.yuaicodemother.constant.UserConstant;
import com.yupi.yuaicodemother.exception.BusinessException;
import com.yupi.yuaicodemother.exception.ErrorCode;
import com.yupi.yuaicodemother.mapper.ChatHistoryMapper;
import com.yupi.yuaicodemother.model.dto.chathistory.ChatHistoryQueryRequest;
import com.yupi.yuaicodemother.model.entity.App;
import com.yupi.yuaicodemother.model.entity.ChatHistory;
import com.yupi.yuaicodemother.model.entity.User;
import com.yupi.yuaicodemother.model.enums.ChatHistoryMessageTypeEnum;
import com.yupi.yuaicodemother.service.AppService;
import com.yupi.yuaicodemother.service.ChatHistoryService;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 对话历史 服务层实现。
 *
 * @author <a href="https://xiaolllei.blog.csdn.net/?type=blog">小雷</a>
 */
@Service
@Slf4j
public class ChatHistoryServiceImpl extends ServiceImpl<ChatHistoryMapper, ChatHistory> implements ChatHistoryService {

    @Lazy
    @Resource
    private AppService appService;

    /**
     * 新增历史消息
     */
    @Override
    public boolean addChatMessage(Long appId, String message, String messageType, Long userId){

        // 参数校验
        if(appId == null || appId < 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        if(StrUtil.isBlank(message)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "消息不能为空");
        }

        if(StrUtil.isBlank(messageType)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "消息类型不能为空！");
        }

        if(userId == null){
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR, "用户未登录！");
        }

        // 验证消息类型是否有效
        ChatHistoryMessageTypeEnum chatHistoryMessageTypeEnum = ChatHistoryMessageTypeEnum.getEnumByValue(messageType);

        if(chatHistoryMessageTypeEnum == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的消息类型！");
        }

        // 使用建造者模式, 构造入库数据 (历史消息)
        ChatHistory chatHistory = ChatHistory.builder()
                .appId(appId)
                .message(message)
                .messageType(messageType)
                .userId(userId)
                .build();

        // 保存到数据库
        boolean result = this.save(chatHistory);
        return result;
    }

    /**
     * 加载对话历史到缓存
     */
    @Override
    public int loadChatHistoryToMemory(Long appId, MessageWindowChatMemory chatMemory, int maxCount){
        // 捕获对话历史加载异常, 不抛出, 保证对话记忆功能执行成功
        try {
            // 拼接查询条件, 查 appId 对应 (最新, maxCount) 条, 降序yu_ai_code_mother
            QueryWrapper queryWrapper = QueryWrapper.create()
                    .eq(ChatHistory::getAppId, appId)
                    // TODO 根据创建时间降序
                    .orderBy(ChatHistory::getCreateTime, false)
                    // TODO 注意起点是 1 而不是 0, 避免本次用户的提示词也作为对话历史
                    .limit(1, maxCount);


            // 查询历史对话表, 获取对话消息列表
            List<ChatHistory> historyList = this.list(queryWrapper);

            // 反转对话消息列表, (旧 maxCount, 最新)
            historyList = historyList.reversed();

            // 清空对话历史缓存, 避免没过期的消息被重复加载
            chatMemory.clear();

            // 按时间顺序, 将对话历史消息加载到缓存
            int loadedCount = 0;
            for(ChatHistory history : historyList){

                // 根据消息类别 user、ai, 依次给加载到缓存中的消息设置类别
                if(ChatHistoryMessageTypeEnum.USER.getValue().equals(history.getMessageType())){
                    chatMemory.add(UserMessage.from(history.getMessage()));
                    loadedCount++;
                }else if(ChatHistoryMessageTypeEnum.AI.getValue().equals(history.getMessageType())){
                    chatMemory.add(AiMessage.from(history.getMessage()));
                    loadedCount++;
                }
            }
            log.info("成功为 appId: {} 加载了 {} 条历史对话", appId, loadedCount);
            return loadedCount;
        } catch (Exception e) {
            log.error("加载历史对话失败，appId: {}, error: {}", appId, e.getMessage(), e);
            // 加载失败不影响系统运行，只是没有历史上下文
            return 0;
        }
    }

    /**
     * 关联删除
     */
    @Override
    public boolean deleteByAppId(Long appId){
        // 参数校验
        if(appId == null || appId < 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 构造删除条件, 删除所有 appId 对应的对话消息
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq("appId", appId);

        // 删除
        return this.remove(queryWrapper);
    }

    @Override
    public QueryWrapper getQueryWrapper(ChatHistoryQueryRequest chatHistoryQueryRequest){
        // 参数校验
        if(chatHistoryQueryRequest == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        // 获取数据
        Long id = chatHistoryQueryRequest.getId();
        String message = chatHistoryQueryRequest.getMessage();
        String messageType = chatHistoryQueryRequest.getMessageType();
        Long appId = chatHistoryQueryRequest.getAppId();
        Long userId = chatHistoryQueryRequest.getUserId();
        LocalDateTime lastCreateTime = chatHistoryQueryRequest.getLastCreateTime();
        int pageNum = chatHistoryQueryRequest.getPageNum();
        int pageSize = chatHistoryQueryRequest.getPageSize();
        String sortField = chatHistoryQueryRequest.getSortField();
        String sortOrder = chatHistoryQueryRequest.getSortOrder();

        // 拼接条件
        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.eq("id", id)
                .eq("appId", appId)
                .like("message", message)
                .eq("messageType", messageType)
                .eq("userId", userId);

        // 游标查询 = appId and <createTime
        if(lastCreateTime != null){
            queryWrapper.lt("createTime", lastCreateTime);
        }

        // TODO 升序/降序条件表示
        if(StrUtil.isNotBlank(sortField)){
            queryWrapper.orderBy(sortField, "ascend".equals(sortOrder));
        }else{
            // 默认按创建事件排序
            queryWrapper.orderBy("createTime", false);
        }
        return queryWrapper;
    }

    @Override
    public Page<ChatHistory> listAppChatHistoryByPage(Long appId,
                                                      int pageSize,
                                                      LocalDateTime lastCreateTime,
                                                      User loginUser){

        // 参数校验
        if(appId == null || appId < 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "appId 错误！");
        }

        // 小于 10 条, 限制爬虫
        if(pageSize < 0  || pageSize > 10){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "只支持一次查询十条数据！");
        }

        // 校验权限, 仅本人或管理员
        boolean isAdmin = loginUser.getUserRole().equals(UserConstant.ADMIN_ROLE);

        App app = appService.getById(appId);

        if(app == null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "应用不存在, 无法找到关联的历史对话！");
        }

        if(!(loginUser.getId().equals(app.getUserId()) || isAdmin)){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "您没有权限查找当前应用的历史对话！");
        }

        // 构造查询请求
        ChatHistoryQueryRequest chatHistoryQueryRequest = new ChatHistoryQueryRequest();
        chatHistoryQueryRequest.setAppId(appId);
        chatHistoryQueryRequest.setLastCreateTime(lastCreateTime);

        // 获取条件
        QueryWrapper queryWrapper = this.getQueryWrapper(chatHistoryQueryRequest);

        // TODO 查询数据, 查符合条件的第一页
        Page<ChatHistory> page = this.page(Page.of(1, pageSize), queryWrapper);

        return page;
    }
}
